#include "widget.h"
#include "./ui_widget.h"
#include <QMessageBox>
#include<Qmap>
#include<stack>
#include<cmath>

Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{
    ui->setupUi(this);
    ui->TextLine->setText("0");
    result = 0;
    waitingForOperand = true;

    ConnectSlots();
    SetShortCutKeys();
}

Widget::~Widget()
{
    delete ui;
}

//bool Widget::Calculate(double operand, QString doing_operator)
//{
//    if(doing_operator =="+")
//    {
//        result += operand;
//    }
//    else if(doing_operator =="-")
//    {
//        result -= operand;
//    }
//    else if(doing_operator =="x")
//    {
//        result *= operand;
//    }
//    else if(doing_operator =="/")
//    {
//        if(operand == 0)
//            return false;
//        result /= operand;
//    }
//    return true;
//}
//
void Widget::AbortOperation()
{

    ui->TextLine->setText("0");
    waitingForOperand = true;
    QMessageBox::warning(this,"运算错误",errorInfo);
}

void Widget::ConnectSlots()
{
    QPushButton *digitBtns[10]={
        ui->Btn0, ui->Btn1, ui->Btn2, ui->Btn3,
        ui->Btn4, ui->Btn5, ui->Btn6, ui->Btn7,
        ui->Btn8, ui->Btn9
    };

    for (auto btn:digitBtns)
    {
            connect(btn, &QPushButton::clicked, this, &Widget::digitClicked);
    }

    QPushButton *operatorBtns[7] ={
        ui->addBtn,
        ui->subBtn,
        ui->mulBtn,
        ui->divisionBtn,
        ui->LeftBracketBtn,
        ui->RightBracketBtn,
        ui->Powbtn
    };

    for(auto btn : operatorBtns)
    {
            connect(btn,&QPushButton::clicked, this, &Widget::operatorClicked);
    }
};

void Widget::digitClicked()
{
    QPushButton *digitBtn = static_cast<QPushButton*>(sender());
    QString value = digitBtn->text();
    if(ui->TextLine->text()=="0"&& value =="0")
            return;
    if(waitingForOperand)
    {
            ui->TextLine->setText(value);
            waitingForOperand = false;
    }
    else
    {
            ui->TextLine->setText(ui->TextLine->text()+ value);
    }
}

void Widget::operatorClicked()
{
    QPushButton *clickedBtn = qobject_cast<QPushButton *>(sender());
    QString clickedoperator = clickedBtn->text();
    ui->TextLine->setText(ui->TextLine->text()+ clickedoperator);
}

void Widget::on_clearBtn_clicked()
{

    QString str = ui->TextLine->text();

    if(str != "0")
    {
            ui->TextLine->setText(str.left((str.length()-1)));
    }
}

void Widget::on_clearAllBtn_clicked()
{
    ui->TextLine->setText("0");
    waitingForOperand = true;

}

void Widget::on_GetValueBtn_clicked()
{
    double result = 0.0;
    try
    {
        result = Compute(inToPost(ui->TextLine->text()));
    }
    catch(const char *er)
    {
        errorInfo =  er;
        AbortOperation();
        return;
    }
    ui->TextLine->setText(ui->TextLine->text()+'='+ QString::number  (result));
    waitingForOperand = true;
}

void Widget::on_signBtn_clicked()
{
    QString text = ui->TextLine->text();
    QChar sign = text[text.size()-1];
    if(sign =='-')
    {
        text.remove(text.size() - 1,1);
    }
    else
    {
        text.append('-');
    }
     ui->TextLine->setText(text);
}

void Widget::on_pointBtn_clicked()
{
     if(waitingForOperand)
        ui->TextLine->setText("0");
     ui->TextLine->setText(ui->TextLine->text()+".");
     waitingForOperand = false;
}

void Widget::keyPressEvent(QKeyEvent* event)
{
    switch(event->key())
    {
    case Qt::Key_0:
        emit ui->Btn0->clicked();
        break;
    case Qt::Key_1:
         ui->Btn1->clicked();
        break;
    case Qt::Key_2:
         ui->Btn2->clicked();
        break;
    case Qt::Key_3:
         ui->Btn3->clicked();
        break;
    case Qt::Key_4:
         ui->Btn4->clicked();
        break;
    case Qt::Key_5:
         ui->Btn5->clicked();
        break;
    case Qt::Key_6:
         ui->Btn6->clicked();
        break;
    case Qt::Key_7:
         ui->Btn7->clicked();
        break;
    case Qt::Key_8:
         ui->Btn8->clicked();
        break;
    case Qt::Key_9:
         ui->Btn9->clicked();
        break;
    case Qt::Key_Plus:
        ui->addBtn->clicked();
        break;
    case Qt::Key_Minus:
        ui->subBtn->clicked();
        break;
    case Qt::Key_Asterisk:
        ui->mulBtn->clicked();
        break;
    case Qt::Key_Slash:
        ui->divisionBtn->clicked();
        break;
    case Qt::Key_Enter:
    case Qt::Key_Equal:
        emit ui->GetValueBtn->clicked();
        break;
    case Qt::Key_Period:
        emit ui->pointBtn->clicked();
        break;
    case Qt::Key_M:
        emit ui->pointBtn->clicked();
        break;
    case Qt::Key_Backspace:
        if(event->modifiers() == Qt::ControlModifier)
        {
            emit ui->clearAllBtn->clicked();
        }
        else
        {
            emit ui->clearBtn->clicked();
        }
    default:
        break;
    }
}

void Widget::SetShortCutKeys()
{
    Qt::Key key[21]={
        Qt::Key_0, Qt::Key_1,Qt::Key_2, Qt::Key_3,Qt::Key_4,Qt::Key_5,Qt::Key_6,Qt::Key_7,Qt::Key_8,Qt::Key_9,
        Qt::Key_Plus, Qt::Key_Minus,Qt::Key_Asterisk,Qt::Key_Slash,
        Qt::Key_Enter, Qt::Key_Period, Qt::Key_Backspace, Qt::Key_M,
        Qt::Key_ParenLeft, Qt::Key_ParenRight,Qt::Key_AsciiCircum
    };

    QPushButton *btn[21]={
        ui->Btn0, ui->Btn1, ui->Btn2,ui->Btn3,
        ui->Btn4, ui->Btn5, ui->Btn6, ui->Btn7,
        ui->Btn8, ui->Btn9,
        ui->addBtn, ui->subBtn, ui->mulBtn, ui->divisionBtn,
        ui->GetValueBtn, ui->pointBtn, ui->clearBtn, ui->signBtn,
        ui->LeftBracketBtn,ui->RightBracketBtn,ui->Powbtn
    };

    for (int i = 0; i < 21; ++i)
    {
        btn[i]->setShortcut(QKeySequence(key[i]));
    }
    ui->clearAllBtn->setShortcut((QKeySequence("Ctrl+Backspace")));
}


QString Widget::inToPost(QString infix)
{
    std::stack<char> stack;
    char currentChar;
    QString postfix;//后缀表达式运算符
    std::map<char,int> priority;//运算符号优先级表
    priority['+']=0;
    priority['-']=0;
    priority['*']=1;
    priority['/'] = 1;
    priority['^']= 2;
    for(int i=0;i<infix.length();i++)//逐个读取中缀表达式字符串中的字符
    {
        currentChar =infix[i].toLatin1();
        if(isdigit(currentChar))//如果是数字直接输出
        {
            postfix.push_back(currentChar);
            continue;
        }
        switch(currentChar)
        {
        case '+':
        case '-':
        case '*':
        case '/':
        case '^':

            if(infix[i-1]!= ')')//如果运算符的前一项不是右括号则说明前一个数字输入完毕，用#标识前面几个字符组成一个数字符串
            {
                if(infix[i-1].isDigit())
                    postfix.push_back('#');
                else
                    throw "表达式不合法";
            }


            if(!stack.empty())//比较目前符号与栈顶符号优先级，低于则出栈，并输出
            {
                char tempTop=stack.top();
                while(tempTop!='(' && priority[currentChar]<=priority[tempTop])
                {
                    stack.pop();
                    postfix.push_back(tempTop);
                    if(stack.empty())
                    {
                        break;
                    }
                    tempTop = stack.top();
                }
            }
            stack.push(currentChar);
            break;

        case '.':
            postfix.push_back(currentChar);
            break;
        case '%':
            postfix.push_back(currentChar);
            break;
        case '(':
            stack.push(currentChar);//左括号直接入栈
            break;
        case ')':
            postfix.push_back('#');//右括号说明前方数字输入完成，标识一下
            char tempTop;
            tempTop=stack.top();
            while(tempTop !='(')//直到栈顶元素是左括号才停止循环
            {
                stack.pop();
                postfix.push_back(tempTop);
                tempTop=stack.top();
            }
            stack.pop();
            break;

        default:
            throw "含有非法操作符";
            break;
        }
    }
    if(infix[infix.size()-1] !=')')
    {
        if(infix[infix.size()-1].isDigit())
            postfix.push_back('#');
        else
            throw "表达式非法";
    }
    while(!stack.empty())
    {
        char tempOut = stack.top();
        stack.pop();
        postfix.push_back(tempOut);
    }
    return postfix;
}

double Widget::Compute(QString s)
{
    std::stack<double> stack;
    QString str;
    double curr;
    double temNum1;double temNum2;
    for(auto i= s.begin();i != s.end();i++)
    {
        if((*i).isDigit())
        {
            str.push_back(*i);
            continue;
        }
        switch((*i).toLatin1())
        {
        case'+':
            temNum1=stack.top(); stack.pop();
            temNum2=stack.top(); stack.pop();
            stack.push(temNum2 + temNum1);
            break;
        case'-':
            temNum1=stack.top(); stack.pop();
            temNum2=stack.top(); stack.pop();
            stack.push(temNum2 - temNum1);
            break;
        case'*':
            temNum1=stack.top(); stack.pop();
            temNum2=stack.top(); stack.pop();
            stack.push(temNum2 * temNum1);
            break;
        case'/':
            temNum1=stack.top(); stack.pop();
            temNum2=stack.top(); stack.pop();
            stack.push(temNum2 / temNum1);
            break;
        case'^':
            temNum1=stack.top(); stack.pop();
            temNum2=stack.top(); stack.pop();
            stack.push(pow(temNum2, temNum1));
            break;
        case'.':
            str.push_back(*i);
            break;
        case '#':
            curr = str.toDouble();
            str.clear();
            stack.push(curr);
            break;
        case '%':
            curr = str.toDouble();
            stack.pop();
            curr *=0.01;
            stack.push(curr);
            break;
        default:
            throw "含有未被定义的操作符";
            break;
        }
    }
    curr = stack.top();
    return curr;
}

